package gouhuo.allbugs.top.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import gouhuo.allbugs.top.mapper.ChatMapper;
import gouhuo.allbugs.top.model.domain.Chat;
import gouhuo.allbugs.top.model.domain.UserTeam;
import gouhuo.allbugs.top.model.vo.ChatVO;
import gouhuo.allbugs.top.model.vo.FriendsMsgVO;
import gouhuo.allbugs.top.service.ChatService;
import gouhuo.allbugs.top.service.FriendsService;
import gouhuo.allbugs.top.service.UserTeamService;
import gouhuo.allbugs.top.utils.ChatKeyUtil;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static gouhuo.allbugs.top.constant.RedisConstants.CHAT_LIST_TTL;
import static gouhuo.allbugs.top.constant.RedisConstants.CHAT_MSG_KET;

/**
 * @author 15294780204
 * @description 针对表【messages(消息表)】的数据库操作Service实现
 * @createDate 2023-05-01 18:07:13
 */
@Service
public class ChatServiceImpl extends ServiceImpl<ChatMapper, Chat>
        implements ChatService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private UserTeamService userTeamService;

    @Resource
    private FriendsService friendsService;

    @Override
    public void saveChatToRedis(String message, Long fromId, Long toId, Long teamId) {
        String key;
        ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
        HashOperations<String, Object, Object> opsForHash = stringRedisTemplate.opsForHash();
        if (teamId == null) {
            key = ChatKeyUtil.getPriKey(toId, fromId);
            String k = CHAT_MSG_KET + toId + ":msg";
            String hashKey = "friend" + fromId;
            opsForHash.put(k, hashKey, message);
            String statusKey = CHAT_MSG_KET + toId + ":status";
            stringRedisTemplate.opsForSet().add(statusKey, hashKey);
        } else {
            key = ChatKeyUtil.getTeamKey(teamId);
            List<UserTeam> userTeams = userTeamService.list(new QueryWrapper<UserTeam>().eq("teamId", teamId).ne("ties", 0));
            String hashKey = "team" + teamId;
            userTeams.forEach(userTeam -> {
                Long id = userTeam.getUserId();
                String k = CHAT_MSG_KET + id + ":msg";
                opsForHash.put(k, hashKey, message);
                String statusKey = CHAT_MSG_KET + id + ":status";
                stringRedisTemplate.opsForSet().add(statusKey, hashKey);
            });
        }
        opsForList.rightPush(key, message);
        stringRedisTemplate.expire(key, CHAT_LIST_TTL, TimeUnit.HOURS);
    }

    @Override
    public List<ChatVO> priChat(Long toId, Long fromId) {
        Gson gson = new Gson();
        String key = ChatKeyUtil.getPriKey(toId, fromId);
        String statusKey = CHAT_MSG_KET + toId + ":status";
        String hashKey = "friend" + fromId;
        stringRedisTemplate.opsForSet().remove(statusKey, hashKey);
        ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
        List<String> redisList = opsForList.range(key, 0, -1);
        if (redisList != null && !redisList.isEmpty()) {
            return redisList.stream().map(redis -> {
                ChatVO chatVO = gson.fromJson(redis, ChatVO.class);
                if (chatVO.getStatus() == 0 && Objects.equals(chatVO.getToId(), toId)) {
                    chatVO.setStatus(1);
                    opsForList.rightPop(key);
                    opsForList.rightPush(key, gson.toJson(chatVO));
                }
                return chatVO;
            }).collect(Collectors.toList());
        } else {
            QueryWrapper<Chat> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("toId", toId).eq("fromId", fromId).or().eq("toId", fromId).eq("fromId", toId);
            return list(queryWrapper).stream().map(chat -> {
                ChatVO chatVO = BeanUtil.copyProperties(chat, ChatVO.class);
                //将未读的消息设为已读
                if (chatVO.getStatus() == 0 && Objects.equals(chatVO.getToId(), fromId)) {
                    update().setSql("status = 1").eq("id", chatVO.getId()).update();
                }
                //写入redis
                opsForList.rightPush(key, gson.toJson(chatVO));
                stringRedisTemplate.expire(key, CHAT_LIST_TTL, TimeUnit.HOURS);
                return chatVO;
            }).collect(Collectors.toList());
        }
    }

    @Override
    public List<ChatVO> teamChat(Long teamId, Long userId) {
        Gson gson = new Gson();
        String key = ChatKeyUtil.getTeamKey(teamId);
        ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
        List<String> redisList = opsForList.range(key, 0, -1);
        String k = CHAT_MSG_KET + userId + ":status";
        String hashKey = "team" + teamId;
        stringRedisTemplate.opsForSet().remove(k, hashKey);
        if (redisList != null && !redisList.isEmpty()) {
            return redisList.stream().map(redis -> gson.fromJson(redis, ChatVO.class)).collect(Collectors.toList());
        } else {
            List<Chat> list = list(new QueryWrapper<Chat>().eq("teamId", teamId));
            return list.stream().map(chat -> {
                ChatVO chatVO = BeanUtil.copyProperties(chat, ChatVO.class);
                opsForList.rightPush(key, gson.toJson(chatVO));
                stringRedisTemplate.expire(key, CHAT_LIST_TTL, TimeUnit.HOURS);
                return chatVO;
            }).collect(Collectors.toList());
        }
    }

    @Override
    public String chatStatus(Long userId) {
        String statusKey = CHAT_MSG_KET + userId + ":status";
        Set<String> members = stringRedisTemplate.opsForSet().members(statusKey);
        if (members == null) return null;
        StringBuffer str = new StringBuffer();
        for (String m : members) {
            if (m.contains("system")) str.append(3);
            else str.append(1);
            String s = str.toString();
            if (s.contains("1") && s.contains("3")) break;
        }
        for (FriendsMsgVO friendsMsgVO : friendsService.msgList(userId)) {
            if (friendsMsgVO.getStatus() == 0) {
                str.append(4);
                return str.toString();
            }
        }
        return str.toString();
    }

    @Override
    public List<ChatVO> chatList(Long userId, Integer scope) {
        List<ChatVO> chatVOList = new ArrayList<>();
        HashOperations<String, Object, Object> opsForHash = stringRedisTemplate.opsForHash();
        String k = CHAT_MSG_KET + userId + ":msg";
        Map<Object, Object> map = opsForHash.entries(k);
        for (Map.Entry<Object, Object> entry : map.entrySet()) {
            String value = String.valueOf(entry.getKey());
            if ((scope == 3 && value.contains("system")) || (scope == 1 && !value.contains("system"))) {
                chatVOList.add(new Gson().fromJson((String) entry.getValue(), ChatVO.class));
            }
        }
        return chatVOList;
    }

    @Override
    public Long chatListDel(Integer scope, Long toId, Long fromId, List<String> list) {
        String key = CHAT_MSG_KET + toId + ":msg";
        HashOperations<String, Object, Object> opsForHash = stringRedisTemplate.opsForHash();
        long del;
        if (scope == 1) {
            del = opsForHash.delete(key, "friend" + fromId);
        } else if (scope == 2) {
            del = opsForHash.delete(key, "team" + fromId);
        } else {
            list.forEach(sys -> opsForHash.delete(key, sys));
            del = 1;
        }
        return del;
    }

}
